use std::env;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::sync::OnceLock;

const DEFAULT_PATH: &str = "/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin";
const SCRIPT_NAME: &str = "get_path.sh";
const COMMON_BIN_DIRS: [&str; 4] = [
    "/opt/homebrew/bin",
    "/opt/homebrew/sbin",
    "/usr/local/bin",
    "/usr/local/sbin",
];

// 缓存PATH结果，避免重复执行耗时的shell脚本
static CACHED_PATH: OnceLock<String> = OnceLock::new();

/// 通过执行shell脚本获取完整的PATH环境变量
/// 使用缓存机制避免重复执行耗时的shell脚本
pub fn get_full_path_from_script() -> String {
    CACHED_PATH
        .get_or_init(|| {
            log::info!("首次获取PATH，执行shell脚本...");
            compute_path()
        })
        .clone()
}

/// 实际计算PATH的函数（仅在首次调用时执行）
fn compute_path() -> String {
    if let Some(script_path) = locate_script() {
        if let Some(full_path) = run_script_file(&script_path) {
            return enrich_with_common_dirs(&full_path);
        }
    } else {
        log::warn!("未找到PATH脚本，无法获取完整PATH");
    }

    log::warn!("无法获取完整PATH，使用默认PATH");
    enrich_with_common_dirs(DEFAULT_PATH)
}

fn run_script_file(path: &Path) -> Option<String> {
    match Command::new("/bin/sh").arg(path).output() {
        Ok(output) => {
            if output.status.success() {
                let full_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
                if !full_path.is_empty() {
                    return Some(full_path);
                }
            } else {
                log::warn!(
                    "脚本执行失败: status={} stderr={}",
                    output.status,
                    String::from_utf8_lossy(&output.stderr)
                );
            }
            None
        }
        Err(err) => {
            log::error!("执行PATH脚本出错: {}", err);
            None
        }
    }
}

fn locate_script() -> Option<PathBuf> {
    // 优化：按优先级顺序检查，找到第一个存在的就返回
    // 这样可以避免检查所有候选路径
    for path in script_candidates() {
        if path.exists() {
            return Some(path);
        }
    }
    log::warn!("PATH脚本候选不存在");
    None
}

fn script_candidates() -> Vec<PathBuf> {
    let mut candidates = Vec::new();

    if let Ok(current_exe) = env::current_exe() {
        if let Some(exe_dir) = current_exe.parent() {
            candidates.push(exe_dir.join("scripts").join(SCRIPT_NAME));

            if let Some(contents_dir) = exe_dir.parent() {
                candidates.push(
                    contents_dir
                        .join("Resources")
                        .join("scripts")
                        .join(SCRIPT_NAME),
                );
            }
        }
    }

    if let Ok(current_dir) = env::current_dir() {
        candidates.push(
            current_dir
                .join("src-tauri")
                .join("scripts")
                .join(SCRIPT_NAME),
        );
        candidates.push(current_dir.join("scripts").join(SCRIPT_NAME));
    }

    candidates
}

fn enrich_with_common_dirs(path: &str) -> String {
    let mut entries: Vec<String> = path
        .split(':')
        .filter(|entry| !entry.trim().is_empty())
        .map(|entry| entry.to_string())
        .collect();

    // 使用HashSet来快速检查是否已存在，避免O(n)的线性搜索
    use std::collections::HashSet;
    let entry_set: HashSet<String> = entries.iter().cloned().collect();
    let mut updated = false;

    for dir in COMMON_BIN_DIRS {
        // 优化：先检查是否已存在，再检查文件系统（文件系统检查更耗时）
        if !entry_set.contains(dir) && Path::new(dir).exists() {
            entries.push(dir.to_string());
            updated = true;
        }
    }

    let enriched = entries.join(":");

    if updated {
        log::info!("PATH 追加常见目录，结果: {}", enriched);
    }

    enriched
}

/// 向前端暴露的命令，用于获取包含用户登录 shell 配置的 PATH
#[tauri::command]
pub async fn get_login_shell_path() -> String {
    get_full_path_from_script()
}
